package com.cloudfun.campusshare.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.cloudfun.campusshare.common.constant.AppStatus;
import com.cloudfun.campusshare.common.constant.ApplicationType;
import com.cloudfun.campusshare.common.constant.Code;
import com.cloudfun.campusshare.common.exception.BusinessException;
import com.cloudfun.campusshare.common.model.AccessToken;
import com.cloudfun.campusshare.common.model.vo.AppEditVO;
import com.cloudfun.campusshare.common.model.vo.AppInfoVO;
import com.cloudfun.campusshare.common.model.vo.AppVO;
import com.cloudfun.campusshare.common.response.BaseResult;
import com.cloudfun.campusshare.common.response.BaseResultFactory;
import com.cloudfun.campusshare.common.security.AuthenticationHolder;
import com.cloudfun.campusshare.dao.AppDao;
import com.cloudfun.campusshare.entity.AppEntity;
import com.cloudfun.campusshare.entity.AuditEntity;
import com.cloudfun.campusshare.entity.DeviceEntity;
import com.cloudfun.campusshare.entity.UserEntity;
import com.cloudfun.campusshare.repo.AppEntityRepo;
import com.cloudfun.campusshare.repo.DeviceEntityRepo;
import com.cloudfun.campusshare.repo.UserEntityRepo;
import com.cloudfun.campusshare.service.AppService;
import com.cloudfun.campusshare.service.ApplicationService;
import com.cloudfun.campusshare.service.TokenFactory;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;

import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.UUID;

/**
 * @author linyangping
 * @date 2019/11/6
 */
@Service
@Slf4j
public class AppServiceImpl implements AppService {

    @Autowired
    private AppEntityRepo appEntityRepo;

    @Autowired
    private TokenFactory tokenFactory;

    @Autowired
    private AppDao appDao;

    @Autowired
    private ApplicationService applicationService;

    @Autowired
    private UserEntityRepo userEntityRepo;

    @Autowired
    private DeviceEntityRepo deviceEntityRepo;

    @Override
    @Transactional
    public BaseResult<?> add(AppVO appVo) throws Exception {
        AppEntity appEntity;
        String appId = appVo.getAppId();
        if (StringUtils.isBlank(appId)) {
            // id为空 创建
            appEntity = new AppEntity();
        } else {
            // 如果Id不为空 则是草稿或者重复提交
            Optional<AppEntity> appEntityOpt = appEntityRepo.findById(appId);
            if (!appEntityOpt.isPresent()) {
                return BaseResultFactory.produceEmptyResult(Code.NODATA);
            }
            appEntity = appEntityOpt.get();
        }
        // 判断应用名是否存在，不查询草稿
        AppEntity fApp = appEntityRepo.findByNameAndStatusNot(appVo.getName(), AppStatus.DRAFT.getCode());
        // 不为空也不等于自己 则重复了
        if (!ObjectUtils.isEmpty(fApp) && !fApp.getId().equals(appId)) {
            return BaseResultFactory.produceEmptyResult(Code.APP_NAME_EXIST);
        }

        BeanUtil.copyProperties(appVo, appEntity);

        // 生成应用appkey
        if (StringUtils.isBlank(appEntity.getAppKey())) {
            appEntity.setAppKey(UUID.randomUUID().toString());
        }
        if (StringUtils.isBlank(appEntity.getSecretKey())) {
            appEntity.setSecretKey(UUID.randomUUID().toString());
        }
        appEntity.setStatus(AppStatus.CREATE_APPLYING.getCode());
        appEntity.setUserId(AuthenticationHolder.getUserId());
        appEntity.setCreateTime(String.valueOf(System.currentTimeMillis()));
        appEntity = appEntityRepo.save(appEntity);
        UserEntity userEntity = userEntityRepo.findById(AuthenticationHolder.getUserId()).orElse(null);
        // 发起申请
        applicationService.create(ApplicationType.APP_CREATE, appEntity.getId(),
                Arrays.asList(userEntity.getEnterpriseName(), appEntity.getName(), appEntity.getDescription(), appEntity.getAppVersion(), appEntity.getVersionDesc()));
        return BaseResultFactory.produceResult(Code.SUCCESS, appEntity.getId());
    }

    @Override
    public BaseResult<?> edit(AppEditVO appVo) throws BusinessException {

        String appId = appVo.getAppId();
        AppEntity appEntity = appEntityRepo.findByUserIdAndId(AuthenticationHolder.getUserId(), appId);
        if (null == appEntity) {
            return BaseResultFactory.produceEmptyResult(Code.APP_NOT_FOUND);
        }
        if (StringUtils.isNotBlank(appVo.getName()) && !appVo.getName().equals(appEntity.getName())) {
            // 只有草稿允许修改应用名
            if (AppStatus.DRAFT.getCode() == appEntity.getStatus()) {
                appEntity.setName(appVo.getName());
            } else {
                return BaseResultFactory.produceResult(Code.ERROR, "不允许修改应用名");
            }
        }

        //设置修改字段
        appEntity.setDescription(appVo.getDescription());
        appEntity.setAppVersion(appVo.getAppVersion());
        appEntity.setVersionDesc(appVo.getVersionDesc());
        appEntityRepo.save(appEntity);
        return BaseResultFactory.produceEmptyResult(Code.SUCCESS);
    }

    @Override
    public BaseResult<?> getAppInfo(String appId) throws BusinessException {
        AppEntity app = appEntityRepo.findByUserIdAndId(AuthenticationHolder.getUserId(), appId);
        if (null == app) {
            return BaseResultFactory.produceEmptyResult(Code.SUCCESS);
        }
        AuditEntity auditEntity = null;
        // 创建失败或者转生产失败 填写失败原因
        if (app.getStatus() == AppStatus.CREATE_APPLY_FAILED.getCode()) {
            auditEntity = applicationService.getLatestAuditByBizIdAndType(appId, ApplicationType.APP_CREATE);
        }
        if (app.getStatus() == AppStatus.TO_PROD_APPLY_FAILED.getCode()) {
            auditEntity = applicationService.getLatestAuditByBizIdAndType(appId, ApplicationType.APP_TO_PROD);
        }
        AppInfoVO appInfoVO = AppInfoVO.builder()
                .appId(app.getId())
                .name(app.getName())
                .appKey(app.getAppKey())
                .secretKey(app.getSecretKey())
                .prodAppKey(app.getProdAppKey())
                .prodSecretKey(app.getProdSecretKey())
                .description(app.getDescription())
                .status(app.getStatus())
                .version(app.getAppVersion())
                .versionDesc(app.getVersionDesc())
                .build();
        if (null != auditEntity) {
            appInfoVO.setAuditDesc(auditEntity.getRemark());
        }
        if (app.getStatus() == AppStatus.CREATE_APPLY_FAILED.getCode()) {
            // 未通过创建审核的隐藏appKey appSecret
            appInfoVO.setAppKey(null);
            appInfoVO.setSecretKey(null);
        }
        return BaseResultFactory.produceResult(Code.SUCCESS, appInfoVO);
    }

    @Override
    public BaseResult<?> queryAppList(Pageable pageable, String value) throws BusinessException {
        return BaseResultFactory.produceResult(Code.SUCCESS, appDao.findByCondition(pageable, value));

    }

    @Override
    @SneakyThrows
    public BaseResult<?> getAccessToken(String appKey, String secret) {

        AppEntity appEntity = appEntityRepo.findByAppKey(appKey);
        if (null == appEntity) {
            return this.getProdAccessToken(appKey, secret);
        }
        log.info("appkey: " + appKey + " , appsecret: " + secret);

        log.info("appEntity: " + appEntity);

        if (ObjectUtils.isEmpty(appEntity) || !secret.equals(appEntity.getSecretKey())) {
            return BaseResultFactory.produceResult(Code.APP_KEY_OR_SECRET_ERROR, "app key 或者 secret 有问题");
        }
        if (appEntity.getStatus() < AppStatus.CREATE_APPLY_SUCCESS.getCode()) {
            return BaseResultFactory.produceResult(Code.APP_PERMISSION_DENIED, "app 审核未通过，没有权限");
        }
        // 验证成功
        AccessToken accessToken = new AccessToken();
        accessToken.setUserId(appEntity.getUserId());
        accessToken.setAppKey(appKey);
        accessToken.setSecretKey(appEntity.getSecretKey());
        // 设置获取时间
        accessToken.setTimestamp(System.currentTimeMillis());
        String accessStr = tokenFactory.createAccessStrWithSecret(accessToken, accessToken.getSecretKey());

        return BaseResultFactory.produceResult(Code.SUCCESS, accessStr);
    }

    /**
     * 获取生产Token
     *
     * @param appKey
     * @param secret
     * @return
     */
    private BaseResult<?> getProdAccessToken(String appKey, String secret) {
        AppEntity appEntity = appEntityRepo.findByProdAppKey(appKey);
        if (null == appEntity || !secret.equals(appEntity.getProdSecretKey())) {
            return BaseResultFactory.produceResult(Code.APP_KEY_OR_SECRET_ERROR, "app key 或者 secret 有问题");
        }
        if (appEntity.getStatus() < AppStatus.TO_PROD_APPLY_SUCCESS.getCode()) {
            return BaseResultFactory.produceResult(Code.APP_PERMISSION_DENIED, "app转生产审核未通过，没有权限");
        }
        // 验证成功
        AccessToken accessToken = new AccessToken();
        accessToken.setUserId(appEntity.getUserId());
        accessToken.setAppKey(appKey);
        accessToken.setSecretKey(appEntity.getProdSecretKey());
        // 设置获取时间
        accessToken.setTimestamp(System.currentTimeMillis());
        String accessStr = tokenFactory.createAccessStrWithSecret(accessToken, accessToken.getSecretKey());

        return BaseResultFactory.produceResult(Code.SUCCESS, accessStr);
    }

    @Override
    @Transactional
    public BaseResult<?> delete(String appId) {
        AppEntity appEntity = appEntityRepo.findByUserIdAndId(AuthenticationHolder.getUserId(), appId);
        // 先删除申请
        applicationService.deleteByBizId(appId);
        // 设置设备appId
        List<DeviceEntity> deviceEntities = deviceEntityRepo.findByAppId(appId);
        for (DeviceEntity deviceEntity : deviceEntities) {
            deviceEntity.setAppId(null);
        }
        deviceEntityRepo.saveAll(deviceEntities);
        appEntityRepo.delete(appEntity);
        return BaseResultFactory.produceEmptyResult(Code.SUCCESS);
    }

    @Override
    @Transactional
    public BaseResult<?> saveAppDraft(AppVO appVo) {
        AppEntity appEntity = new AppEntity();
        BeanUtil.copyProperties(appVo, appEntity);
        appEntity.setStatus(AppStatus.DRAFT.getCode());
        appEntity.setUserId(AuthenticationHolder.getUserId());
        appEntity = appEntityRepo.save(appEntity);
        return BaseResultFactory.produceResult(Code.SUCCESS, appEntity.getId());
    }

    @Override
    public BaseResult<String> toProd(String appId) {
        AppEntity appEntity = appEntityRepo.findByUserIdAndId(AuthenticationHolder.getUserId(), appId);
        if (null == appEntity) {
            return BaseResultFactory.produceResult(Code.NODATA, "");
        }
        int status = appEntity.getStatus();
        if (AppStatus.CREATE_APPLY_SUCCESS.getCode() != status
                && AppStatus.TO_PROD_APPLY_SUCCESS.getCode() != status
                && AppStatus.TO_PROD_APPLY_FAILED.getCode() != status) {
            return BaseResultFactory.produceResult(Code.ERROR, "应用状态错误");
        }
        appEntity.setStatus(AppStatus.TO_PROD_APPLYING.getCode());
        appEntityRepo.save(appEntity);
        UserEntity userEntity = userEntityRepo.findById(AuthenticationHolder.getUserId()).orElse(null);
        // 发起申请
        applicationService.create(ApplicationType.APP_TO_PROD, appEntity.getId(),
                Arrays.asList(userEntity.getEnterpriseName(), appEntity.getName(), appEntity.getDescription(), appEntity.getAppVersion(), appEntity.getVersionDesc()));
        return BaseResultFactory.produceResult(Code.SUCCESS, "");
    }

    @Override
    public void onToProdSuccess(AppEntity appEntity) {
        appEntity.setProdAppKey(UUID.randomUUID().toString());
        appEntity.setProdSecretKey(UUID.randomUUID().toString());
    }
}
